package pt.inescid.components.policyengine.heimdall.pip;

import java.util.Vector;

import pt.inescid.components.policyengine.heimdall.pdp.base.CesInstance;

public class PIPCache {
	
	private static long maxMemUsage = 100 * 1024* 1024;
	
	// A Vector of cachedModels
	private static Vector allCachedModels = new Vector();
	
	/* ===========================================================
	==============================================================
	=============                    =============================
	=============      getEvents       =============================
	=============                    =============================
	==============================================================
	=========================================================== */
	public static Vector getEvents(String modelDefTag, 
			String cesName, 
			Vector cesParameters,
			NodeInfo currentNode) {

		CachedModel currentModel = null;
		for (int i = 0; i < allCachedModels.size(); i++) {
			currentModel = (CachedModel) allCachedModels.elementAt(i);
			
			// check if a similar model is loaded
			if (currentModel.getModelDefTag().equals(modelDefTag)) {
				
				return (currentModel.getEvents(cesName,
						cesParameters, currentNode)); 
			}
		}
		
		return (null);
	} // getEvents

	
	
	/* ===========================================================
	==============================================================
	=============                    =============================
	=============      updateEventsFromRemoteNode       =============================
	=============                    =============================
	==============================================================
	=========================================================== */
	public static void updateEventsFromRemoteNode(
			String modelDefTag, 
			String cesTag, 
			NodeInfo currentNode,
			Vector newEvents) {

		CachedModel currentModel = null;
		boolean found = false;
		for (int i = 0; i < allCachedModels.size(); i++) {
			currentModel = (CachedModel) allCachedModels.elementAt(i);
			
			// check if a similar model is loaded
			if (currentModel.getModelDefTag().equals(modelDefTag)) {
				i = allCachedModels.size();
				found = true;
			}
		}
		
		if (found) {
			currentModel.updateEventsFromRemoteNode(cesTag, currentNode,
					newEvents);
		}
	}
	
	
	
	/* ===========================================================
	==============================================================
	=============                    =============================
	=============      updateEventsFromLocalNode       =============================
	=============                    =============================
	==============================================================
	=========================================================== */
	public static void updateEventsFromLocalNode(
			String modelDefTag, 
			CesInstance thisCes, 
			NodeInfo currentNode,
			Vector newEvents) {

		CachedModel currentModel = null;
		boolean found = false;
		for (int i = 0; i < allCachedModels.size(); i++) {
			currentModel = (CachedModel) allCachedModels.elementAt(i);
			
			// check if a similar model is loaded
			if (currentModel.getModelDefTag().equals(modelDefTag)) {
				i = allCachedModels.size();
				found = true;
			}
		}
		
		if (!found) {
			currentModel = new CachedModel(modelDefTag);
			allCachedModels.add(currentModel);
		}
		
		currentModel.updateEventsFromLocalNode(thisCes, currentNode,
				newEvents);
	} // updateEvents

	
	
	/* ===========================================================
	==============================================================
	=============                    =============================
	=============      checkMemUsage       =============================
	=============                    =============================
	==============================================================
	=========================================================== */
	public static void checkMemUsage() {
		
		CachedModel currentModel = null;
		int minimumCui = Integer.MAX_VALUE;
		int currentCui = minimumCui;
		CachedModel minimumCuiModel = null;
		
		Runtime rt = Runtime.getRuntime();
		rt.gc();
		long usedMemory = rt.totalMemory() - rt.freeMemory();
		
		while (usedMemory > maxMemUsage) { 
			for (int i = 0; i < allCachedModels.size(); i++) {
				currentModel = (CachedModel) allCachedModels.elementAt(i);
				currentCui = currentModel.getMinimumCui();
				
				if (currentCui < minimumCui) {
					minimumCui = currentCui;
					minimumCuiModel = currentModel;
				}
			}
			
			if (minimumCuiModel != null) {
				minimumCuiModel.discardMinimumCui(minimumCui);
			}
			else {
				return;
			}
			
			rt.gc();
			usedMemory = rt.totalMemory() - rt.freeMemory();
		}
		
		for (int i = 0; i < allCachedModels.size(); i++) {
			currentModel = (CachedModel) allCachedModels.elementAt(i);

			currentModel.decreaseCui();
		}
	}
	
}; // PIPCache
